package com.wang.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wang.config.RabbitMQConfig;
import com.wang.enums.*;
import com.wang.exception.BizException;
import com.wang.feign.ProductOrderFeignService;
import com.wang.interceptor.LoginInterceptor;
import com.wang.mapper.CouponMapper;
import com.wang.mapper.CouponTaskMapper;
import com.wang.model.*;
import com.wang.mapper.CouponRecordMapper;
import com.wang.request.LockCouponRecordsRequest;
import com.wang.request.NewUserCouponRequest;
import com.wang.service.CouponRecordService;
import com.wang.util.JsonData;
import com.wang.vo.CouponRecordVO;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 落日孤城
 * @since 2025-05-10
 */
@Service
@Slf4j
public class CouponRecordServiceImpl  implements CouponRecordService {
    @Autowired
    private CouponRecordMapper couponRecordMapper;

    @Autowired
    private CouponTaskMapper couponTaskMapper;

    @Autowired
    private RabbitMQConfig rabbitMQConfig;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private ProductOrderFeignService productOrderFeignService;


    /**
     * 分页查询优惠券领取记录
     *
     * @param page
     * @param size
     * @return
     */
    @Override
    public Map<String, Object> page(Integer page, Integer size) {
        LoginUser loginUser = LoginInterceptor.threadLocal.get();
        Page<CouponRecordDO> pageInfo = new Page<>(page, size);
        Page<CouponRecordDO> couponRecordDOPage = couponRecordMapper.selectPage(pageInfo, new QueryWrapper<CouponRecordDO>()
                .eq("user_id", loginUser.getId())
                .orderByDesc("create_time"));
        Map<String, Object> result = new HashMap<>();
        result.put("total_record", couponRecordDOPage.getTotal());
        result.put("total_page", couponRecordDOPage.getPages());
        result.put("current_data", couponRecordDOPage.getRecords().stream().map(obj -> beanProcess(obj)).collect(Collectors.toList()));

        return result;
    }

    /**
     * 根据优惠券领取记录id查询优惠券领取记录详情
     *
     * @param recordId
     * @return
     */
    @Override
    public CouponRecordVO findById(Integer recordId) {
        LoginUser loginUser = LoginInterceptor.threadLocal.get();
        CouponRecordDO couponRecordDO = couponRecordMapper.selectOne(new QueryWrapper<CouponRecordDO>()
                .eq("id", recordId)
                .eq("user_id", loginUser.getId()));
        if (couponRecordDO == null) {
            return null;
        }
        return beanProcess(couponRecordDO);
    }

    /**
     * 一：锁定优惠券表记录
     * 二：task表插入记录
     * 三：发送延迟消息
     *
     * @param lockCouponRecordsRequest
     * @return
     */
    @Override
    public JsonData lockCouponRecords(LockCouponRecordsRequest lockCouponRecordsRequest) {
        LoginUser loginUser = LoginInterceptor.threadLocal.get();
        List<Long> lockCouponRecordIds = lockCouponRecordsRequest.getLockCouponRecordIds();
        String orderOutTradeNo = lockCouponRecordsRequest.getOrderOutTradeNo();

        //一：批量更新优惠券记录
        int updateRows = couponRecordMapper.lockUseStateBatch(loginUser.getId(), CouponUserStateEnum.USED.name(), lockCouponRecordIds);


        //二：批量插入task表
        List<CouponTaskDO> couponTaskDOS = lockCouponRecordIds.stream().map(obj -> {
            CouponTaskDO couponTaskDO = new CouponTaskDO();
            couponTaskDO.setCreateTime(new Date());
            couponTaskDO.setCouponRecordId(obj);
            couponTaskDO.setOutTradeNo(orderOutTradeNo);
            couponTaskDO.setLockState(StockTaskStateEnum.LOCK.name());
            return couponTaskDO;
        }).collect(Collectors.toList());
        int instertRows = couponTaskMapper.insertBatch(couponTaskDOS);

        if (updateRows == lockCouponRecordIds.size() && instertRows == lockCouponRecordIds.size()) {
            //三：发送延迟消息
            for (CouponTaskDO couponTaskDO : couponTaskDOS) {
                CouponRecordMessage couponRecordMessage = new CouponRecordMessage();
                couponRecordMessage.setOutTradeNo(orderOutTradeNo);
                couponRecordMessage.setTaskId(couponTaskDO.getId());

                rabbitTemplate.convertAndSend(rabbitMQConfig.getEventExchange(), rabbitMQConfig.getCouponReleaseDelayRoutingKey(), couponRecordMessage);
                log.info("优惠券锁定消息发送成功:{}", couponRecordMessage.toString());
            }


            return JsonData.buildSuccess();
        } else {
            throw new BizException(BizCodeEnum.COUPON_RECORD_LOCK_FAIL);
        }

    }

    /**
     * 优惠券释放
     *
     * @param recordMessage
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public boolean releaseCouponRecord(CouponRecordMessage recordMessage) {
        Long taskId = recordMessage.getTaskId();
        //查询task表中数据的状态
        CouponTaskDO couponTaskDO = couponTaskMapper.selectOne(new QueryWrapper<CouponTaskDO>().eq("id", taskId));
        if (couponTaskDO == null) {
            log.warn("工作单不存，消息:{}", recordMessage);
            return true;
        }
        //task表中数据状态为lock时才进行处理  （三种状态：lock锁定、finish完成、cancel取消）设置取消状态而不是直接删除的原因：方便后面如果有分析时，这个是一个宝贵的数据
        if (couponTaskDO.getLockState().equals(StockTaskStateEnum.LOCK.name())) {
            //查询订单表中数据的支付状态   （三种支付状态：NEW 未支付订单,PAY已经支付订单,CANCEL超时取消订单）
            JsonData jsonData = productOrderFeignService.queryProductOrderState(recordMessage.getOutTradeNo());
            if (jsonData.getCode() == 0) {//查询成功

                String state = jsonData.getData().toString();
                if (ProductOrderStateEnum.NEW.name().equalsIgnoreCase(state)) {
                    //如果支付状态是NEW，则重新投递消息到死信队列里   （导致这种情况发生的一些原因：网络问题、服务端处理延迟、消息队列堆积、系统资源不足、代码逻辑问题、配置问题）
                    log.warn("订单状态是NEW,返回给消息队列，重新投递:{}", recordMessage);
                    return false;
                }

                if (ProductOrderStateEnum.PAY.name().equalsIgnoreCase(state)) {
                    //如果已经支付，修改task状态为finish
                    couponTaskDO.setLockState(StockTaskStateEnum.FINISH.name());
                    couponTaskMapper.update(couponTaskDO, new QueryWrapper<CouponTaskDO>().eq("id", recordMessage.getTaskId()));
                    log.info("订单已经支付，修改库存锁定工作单FINISH状态:{}", recordMessage);
                    return true;
                }
            }

            //订单不存在，或者订单被取消，确认消息,修改task状态为CANCEL,恢复优惠券使用记录为NEW
            log.warn("订单不存在，或者订单被取消，确认消息,修改task状态为CANCEL,恢复优惠券使用记录为NEW,message:{}",recordMessage);
            couponTaskDO.setLockState(StockTaskStateEnum.CANCEL.name());

            couponTaskMapper.update(couponTaskDO,new QueryWrapper<CouponTaskDO>().eq("id",recordMessage.getTaskId()));
            //恢复优惠券记录是NEW状态
            couponRecordMapper.updateState(couponTaskDO.getCouponRecordId(),CouponUserStateEnum.NEW.name());

            return true;
        } else {
            //task表数据是其他情况打印日志
            log.warn("工作单状态不是LOCK,state={},消息体={}", couponTaskDO.getLockState(), recordMessage);
            return true;
        }
    }


    private CouponRecordVO beanProcess(CouponRecordDO couponRecordDO) {
        CouponRecordVO couponRecordVO = new CouponRecordVO();
        BeanUtils.copyProperties(couponRecordDO,couponRecordVO);
        return couponRecordVO;
    }

}
